// ~ 运算符 位运算符 位非运算符 二进制取反 ~5 => -6 先将5转换为二进制 0000 0101 然后取反 1111 1010 再转换为十进制 -6
// ~~ 号类似 Math.floor() 但是性能更高
// const mode = 91122313.3434 % 1000
// console.log(~~mode, mode) // 313 313.3434

// 数字转千分位的几个函数处理实现 即 1000000 => 1,000,000

// 第一种：将数字转为字符串 然后根据小数点.分割数字，然后将整数部分从后往前每三位加一个逗号
// 整数的长度开始循环，length为长度，则length-1为最后一位的索引，length-2为倒数第二位的索引，以此类推
// 当 length-n为3的倍数时，则表示需要添加','号 当索引为0时，说明已经到了最高位，不需要再加逗号
// console.log(Number(null)) // 0
// console.log(~~-60.6) // -60
const format_with_reverse = number => {
	// 按照小数点.分割数字
	const parts = number.toString().split('.')
	// 整数部分
	const int = parts[0] + ''
	// 整数部分的长度
	const len = int.length
	let str = ''
	for (let i = len - 1; i >= 0; i--) {
		str = int[i] + str
		if ((len - i) % 3 === 0 && i !== 0) {
			str = ',' + str
		}
	}
	return str + (parts[1] ? '.' + parts[1] : '')
}

// console.log(format_with_reverse(1000000.123)) // 1,000,000

// 第二种：将数字转为字符串，然后使用substring方法截取整数部分字符串，每三位加一个逗号
// substring 截取函数，start为开始位置索引，end为结束位置索引，不包含end位置的字符
const format_with_substring = number => {
	// 按照小数点.分割数字
	const parts = number.toString().split('.')
	// 整数部分
	const int = parts[0] + ''
	// 整数部分的长度按3取模，获取到高位不需要处理的部分的长度
	const mod = int.length % 3
	let str = int.substring(0, mod)
	for (let i = mod; i < int.length; i += 3) {
		str += `,${int.substring(i, i + 3)}` // 每隔三位加一个逗号
	}
	// 如果取模结果为0，说明整数部分的长度是3的倍数，最高位不需要处理，所以需要去掉最高位的逗号
	if (mod === 0) {
		str = str.replace(/^,/, '')
	}

	return str + (parts[1] ? '.' + parts[1] : '')
}
// console.log(format_with_substring(1000000)) // 1,000,000

// 第三种：求整+求商+求模 循环处理：
// 1 数字取整数部分
// 2 求商 用整数部分除以1000，得到商
// 3 若商大于等于1，则对数字求模1000，得到余数，左侧补0，然后将余数和结果拼接
// 4 若商小于1，则将商和结果拼接，并结束循环
const format_with_mod = number => {
	// 取小数部分
	const decimal = number.toString().split('.')?.[1]
	// 取整数部分
	let int = ~~number
	let str = ''
	do {
		// 求对1000的余数
		let mod = `${int % 1000}`
		// 求商
		int = ~~(int / 1000)
		// 商大于等于1的情况表示还能继续循环，否则就表示不能循环了，不需要再补0
		if (int >= 1) {
			mod = mod.padStart(3, '0')
		}
		// 不是第一次循环，需要加逗号
		if (str) {
			str = mod + ',' + str
		} else {
			str = mod
		}
	} while (int >= 1)
	return `${str}${decimal ? '.' + decimal : ''}`
}

// console.log(format_with_mod(1987654321.123456789))

// 第四种：国际化数字处理方案 Intl.NumberFormat 传入最大小数位数和最小小数位数会提升性能
const number = 121231233456.789
const numberFormat = new Intl.NumberFormat('en-us', {
	maximumFractionDigits: 2, // 最大小数位数
	minimumFractionDigits: 2 // 最小小数位数
})
console.log(numberFormat.format(number)) // 123,456.789

// Number Obj toLocaleString 方法 底层使用的是Intl.NumberFormat
console.log(
	number.toLocaleString('en-us', {
		maximumFractionDigits: 2, // 最大小数位数
		minimumFractionDigits: 2 // 最小小数位数
	})
)
